package com.eugenema.windowGui.controller;

import com.eugenema.demand.Demand;
import com.eugenema.demand.impl.DemandF2Schedule;
import com.eugenema.demand.impl.DemandF5FillMatchResult;
import com.eugenema.demand.impl.DemandF5RedGemBook;
import com.eugenema.demand.impl.DemandF5Schedule;
import com.eugenema.entity.ParameterMap;
import com.eugenema.runMain.StartMain;
import com.eugenema.util.ConfigUtil;
import com.eugenema.util.FileListener;
import com.eugenema.util.SeleniumUtil;
import com.eugenema.util.SeleniumXmlParseUtil;
import com.eugenema.windowGui.MainApplication;
import com.jfoenix.controls.*;
import com.jfoenix.controls.JFXDialog.DialogTransition;
import com.jfoenix.controls.cells.editors.TextFieldEditorBuilder;
import com.jfoenix.controls.cells.editors.base.GenericEditableTreeTableCell;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import com.jfoenix.effects.JFXDepthManager;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;
import static javafx.animation.Interpolator.EASE_BOTH;

/**
 * 首页详情
 * 执行程序入口
 *
 * @author Eugenema
 * @date 2023/3/27 22:14
 **/
@ViewController(value = "/fxml/homeDetail.fxml", title = "首页详情")
public class HomeDetailController {
    private static Logger logger = LoggerFactory.getLogger(HomeDetailController.class);

    /** 当前打开的配置文件 */
    public static String openingConfigFile = "";
    /** 当前打开的配置文件参数 key */
    public static String openingConfigParameterKey = "";
    /** 当前打开的配置文件 key */
    public static String openingConfigKey = "";
    /** 主界面 */
    private Stage stage;
    /** 视图流上下文 */
    @FXMLViewFlowContext
    private ViewFlowContext context;
    /** 进度条 */
    @FXML
    private JFXProgressBar progressBar;
    /** 进度条指示标签 */
    @FXML
    private Label progressLabel;
    /** 进度条数值 */
    private static DoubleProperty progress = null;
    /** 进度增长量，默认 0.1，即需要增长十次才能走完进度条 */
    public static double increaseProgress = 0.1;
    /** 进度条动画 */
    private Timeline timeline;
    /** 需求选择按钮*/
    List<JFXToggleButton> selectButtonList = new ArrayList<>();
    @FXML
    private JFXToggleButton demandOne;
    @FXML
    private JFXToggleButton demandTwo;
    @FXML
    private JFXToggleButton demandThree;
    @FXML
    private JFXToggleButton demandFour;
    /** 启动按钮 */
    @FXML
    private JFXButton startButton;
    /** 提示框 */
    @FXML
    private JFXDialog runTip;
    /** 提示框确认按钮 */
    @FXML
    private JFXButton acceptButton;
    /** 父级区域 */
    @FXML
    private VBox rootVbox;
    /** 日志区域 */
    @FXML
    private TextArea logArea;
    /** 执行信息区域 */
    @FXML
    private GridPane runInfo;
    /** 需求列表 */
    @FXML
    private JFXMasonryPane demandList;
    /** 需求列表滚动条 */
    @FXML
    private ScrollPane scrollPane;
    /** 编辑参数弹窗 */
    @FXML
    private JFXDialog editParameterDialog;
    /** 参数表格 */
    @FXML
    private JFXTreeTableView<ParameterMap> parameterTable;
    /** 名称列 */
    @FXML
    private JFXTreeTableColumn<ParameterMap, String> name;
    /** 链接列 */
    @FXML
    private JFXTreeTableColumn<ParameterMap, String> link;
    /** 配置另存为 */
    @FXML
    private JFXButton saveAsConfigFile;
    /** 加载配置 */
    @FXML
    private JFXButton loadConfigFile;
    /** 增加联赛/球队 按钮 */
    @FXML
    private JFXButton treeTableViewAdd;
    /** 删除选中行 */
    @FXML
    private JFXButton treeTableViewRemove;
    /** 当前打开的联赛 key */
    @FXML
    private Label leagueKey;
    /** 编辑参数弹窗标题：当前打开的联赛配置文件名 */
    @FXML
    private Label editParameterDialogTitle;
    /** 程序运行标志 */
    public static boolean runFlag = false;
    /** 需要执行的需求列表 */
    private List<Boolean> runDemandList = new ArrayList<>();
    /** 参数编辑窗口数据 */
    private ObservableList<ParameterMap> parameterData;
    /** 弹窗关闭确认对话框 */
    Alert confirmAlert;
    /** 执行成功对话框 */
    Alert successAlert;
    /** 异常对话框 */
    Alert repetitionAlert;

    @PostConstruct
    public void init() {
        //初始化文件监听的日志区域对象
        FileListener.logArea = logArea;
        //日志区域自动滚动
        logArea.textProperty().addListener((observable, oldValue, newValue) -> logArea.setScrollTop(Double.MAX_VALUE));

        //获取主界面和场景
        stage = (Stage) context.getRegisteredObject(MainApplication.CONTEXT_KEY_STAGE);

        //将运行信息区域置底
        VBox.setMargin(runInfo, new Insets(70, 0, 0, 0));

        // 生成需求列表
        createDemandList();

        //提示框确认按钮绑定事件，点击后关闭弹窗
        acceptButton.setOnAction(action -> runTip.close());

        //监听进度更改，实时显示当前进度数值
        progressBar.progressProperty().addListener((observable, oldValue, newValue) -> progressLabel.setText(String.format("%.0f%%", newValue.doubleValue() * 100)));

        //初始化进度条数值并创建动画
        progress = progressBar.progressProperty();
        timeline = new Timeline(new KeyFrame(Duration.ZERO, new KeyValue(progressBar.secondaryProgressProperty(), 0)), new KeyFrame(Duration.seconds(1), new KeyValue(progressBar.secondaryProgressProperty(), 1)));
        timeline.setCycleCount(Timeline.INDEFINITE);


        //初始化弹窗关闭确认对话框
        confirmAlert = new Alert(Alert.AlertType.CONFIRMATION);
        confirmAlert.setTitle("确认关闭");
        confirmAlert.setHeaderText("您确定要关闭窗口吗？");
        confirmAlert.setContentText("请点击确定按钮关闭窗口，注意保存已修改数据");

        //初始化执行成功对话框
        successAlert = new Alert(Alert.AlertType.INFORMATION);
        successAlert.setTitle("操作成功");
        successAlert.setHeaderText(null);
        successAlert.setContentText("操作已成功完成！");

        //初始化名称重复对话框
        repetitionAlert = new Alert(Alert.AlertType.ERROR);

        //增加联赛/球队数据按钮点击事件
        treeTableViewAdd.setOnMouseClicked((e) -> {
            parameterData.add(new ParameterMap(leagueKey.getText(), "联赛/球队名字", "链接"));
            final IntegerProperty currCountProp = parameterTable.currentItemsCountProperty();
            currCountProp.set(currCountProp.get() + 1);
        });

        //删除选中行按钮设置只有选中行时才可用，绑定点击事件
        treeTableViewRemove.disableProperty().bind(Bindings.equal(-1, parameterTable.getSelectionModel().selectedIndexProperty()));
        treeTableViewRemove.setOnMouseClicked((e) -> {
            parameterData.remove(parameterTable.getSelectionModel().selectedItemProperty().get().getValue());
            final IntegerProperty currCountProp = parameterTable.currentItemsCountProperty();
            currCountProp.set(currCountProp.get() - 1);
        });

        //绑定列与数据
        setupCellValueFactory(name, ParameterMap::nameProperty);
        setupCellValueFactory(link, ParameterMap::linkProperty);
        //设置列编辑事件
        name.setCellFactory((TreeTableColumn<ParameterMap, String> param) -> new GenericEditableTreeTableCell<>(new TextFieldEditorBuilder()));
        name.setOnEditCommit((TreeTableColumn.CellEditEvent<ParameterMap, String> t) -> t.getTreeTableView().getTreeItem(t.getTreeTablePosition().getRow()).getValue().nameProperty().set(t.getNewValue()));
        link.setCellFactory((TreeTableColumn<ParameterMap, String> param) -> new GenericEditableTreeTableCell<>(new TextFieldEditorBuilder()));
        link.setOnEditCommit((TreeTableColumn.CellEditEvent<ParameterMap, String> t) -> t.getTreeTableView().getTreeItem(t.getTreeTablePosition().getRow()).getValue().linkProperty().set(t.getNewValue()));
        //设置参数编辑窗口可编辑
        parameterTable.setShowRoot(false);
        parameterTable.setEditable(true);
    }

    /**
     * 生成需求列表
     *
     * @author 马寅广
     * @date 2023/12/31 17:13
     *
     **/
    private void createDemandList() {
        ArrayList<Node> children = new ArrayList<>();
        int index = 0;
        for (Demand demand : Demand.demandPool) {
            // 创建阴影
            StackPane child = new StackPane();
            double width = 300;
            double height = 200;
            child.setPrefWidth(width);
            child.setPrefHeight(height);
            child.setScaleX(0);
            child.setScaleY(0);
            JFXDepthManager.setDepth(child, 1);
            children.add(child);

            // 创建标题区域
            StackPane header = new StackPane();
            header.setStyle("-fx-background-radius: 5 5 0 0; -fx-background-color: #DBF2FE");
            VBox.setVgrow(header, Priority.ALWAYS);
            Label headerLabel = new Label();
            headerLabel.setText(demand.getTitle());
            headerLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; -fx-wrap-text: true;");
            headerLabel.setTooltip(new Tooltip(demand.getNotice()));
            header.getChildren().add(headerLabel);

            // 创建功能按钮区域
            GridPane body = new GridPane();
            // 设置列宽和行高
            RowConstraints rowConstraints = new RowConstraints();
            rowConstraints.setVgrow(Priority.ALWAYS);
            rowConstraints.setValignment(VPos.CENTER);
            ColumnConstraints columnConstraints = new ColumnConstraints();
            columnConstraints.setHgrow(Priority.ALWAYS);
            columnConstraints.setHalignment(HPos.CENTER);
            body.getColumnConstraints().add(columnConstraints);
            body.getColumnConstraints().add(columnConstraints);
            body.getRowConstraints().add(rowConstraints);
            body.setPadding(new Insets(10, 10, 10, 10));
            body.setMinHeight(90);
            body.setMaxHeight(90);
            int row = 0;
            int column = 0;
            // 添加按钮
            for (JFXButton button : demand.getButtons()) {
                if (column > 1) {
                    row++;
                    column = 0;
                }
                // 编辑参数按钮绑定方法
                if (button.getId() != null && button.getId().startsWith(Demand.EDIT_PARAMETER_PREFIX)) {
                    button.setOnAction(action -> editParameter(action, demand.getKey()));
                }
                // 自定义弹窗按钮绑定方法
                if (button.getId() != null && button.getId().startsWith(Demand.DIALOG_PREFIX)) {
                    button.setOnAction(action -> showDialog(action, demand.createCustomDialog()));
                }

                // 若该行仅剩一个按钮，则居中显示
                if (column == 0 && row * 2 + column == demand.getButtons().size() - 1) {
                    body.add(button, column++, row, 2, 1);
                } else {
                    body.add(button, column++, row);
                }
            }
            body.setStyle("-fx-background-radius: 0 0 5 5; -fx-background-color: #ffffff;");

            // 创建需求卡片
            VBox content = new VBox();
            content.getChildren().addAll(header, body);

            // 创建选择按钮
            JFXToggleButton selectButton = new JFXToggleButton();
            selectButton.setId(String.valueOf(demand.getOrder()));
            selectButton.getStyleClass().add("custom-jfx-toggle-button");
            selectButton.setEffect(new DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.26), 5, 0.05, 0, 1));
            selectButton.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
                return header.getBoundsInParent().getHeight() - selectButton.getHeight() / 2;
            }, header.boundsInParentProperty(), selectButton.heightProperty()));
            StackPane.setMargin(selectButton, new Insets(0, 0, 0, 12));
            StackPane.setAlignment(selectButton, Pos.TOP_LEFT);
            selectButtonList.add(selectButton);

            // 创建需求卡片出现动画
            Timeline animation = new Timeline(
                    new KeyFrame(Duration.millis(240),
                            new KeyValue(child.scaleXProperty(), 1, EASE_BOTH),
                            new KeyValue(child.scaleYProperty(), 1, EASE_BOTH))
            );
            animation.setDelay(Duration.millis(200 * index + 200));
            animation.play();
            child.getChildren().addAll(content, selectButton);
            index++;
        }
        demandList.getChildren().addAll(children);
        Platform.runLater(() -> scrollPane.requestLayout());
        Platform.runLater(() -> scrollPane.requestLayout());
        JFXScrollPane.smoothScrolling(scrollPane);

        // 设置界面元素高度
        scrollPane.setMinHeight((MainApplication.height - 200) * 0.6);
        runInfo.setMinHeight((MainApplication.height - 200) * 0.4);
    }

    /**
     * 启动，开始执行需求
     *
     * @author Eugenema
     *
     * @date 2023/4/11 22:04
     **/
    @FXML
    private void demandStart() {
        //没有要执行的需求
        if (selectButtonList.stream().noneMatch(ToggleButton::isSelected)) {
            runTip.setTransitionType(DialogTransition.CENTER);
            runTip.show((StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_MAIN_CONTENT));
            return;
        }

        // 不能同时运行
        if (runFlag) {
            logger.warn("当前已有任务在运行中，请等待！");
            return;
        }

        //更改运行标志，按钮禁用
        setComponentDisable(true);

        //执行需求
        StartMain.threadPool.submit(() -> {
            try {
                for (JFXToggleButton button : selectButtonList) {
                    if (button.isSelected()) {
                        Demand.demandPool[Integer.parseInt(button.getId())].run();
                    }
                }
                //运行完成，恢复运行标志，按钮可编辑
                setComponentDisable(false);
            } catch (Exception e) {
                //更改运行标志，但不恢复其他
                runFlag = false;
                logger.error("执行需求失败：", e);
            }
        });
    }

    /**
     * 启动或结束时，执行的动作
     * <br/>1、界面禁用状态
     * <br/>2、运行标志
     * <br/>3、窗口置顶
     * <br/>4、进度条置零或置一
     * <br/>5、清空日志区域
     * <br/>6、关闭浏览器
     * <br/>7、显示/关闭加载图
     *
     * @param flag 运行状态，false 为结束，true 为开始
     * @author Eugenema
     * @date 2023/4/16 22:48
     **/
    private void setComponentDisable(boolean flag) {
        //运行标志
        runFlag = flag;
        //窗口置顶/取消置顶
//        setWindowTop(flag);
        //关闭浏览器
        SeleniumUtil.quitBrowser();

        //JavaFX 进程更新进度信息
        Platform.runLater(() -> {
            //进度条赋初值
            progress.set(flag ? 0 : 1);
            //恢复/禁用：需求列表、启动按钮、侧边栏区；清空日志区域
            MainController.switchNode(!flag, (StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_SIDE_MENU), demandList, startButton);
            if (flag) {
                //清空日志区域内容
                logArea.clear();
                //进度条动画
                timeline.play();
            } else {
                //进度条动画
                timeline.stop();
            }
        });
    }

    /**
     * 设置窗口置顶状态
     *
     * @param flag 是否置顶
     * @author Eugenema
     * @date 2023/4/16 23:20
     **/
    private void setWindowTop(boolean flag) {
        //在 JavaFx 线程中更新窗口置顶状态
        Platform.runLater(() -> ((Stage) context.getRegisteredObject(MainApplication.CONTEXT_KEY_STAGE)).setAlwaysOnTop(flag));
    }

    /**
     * 进度条增加一次
     * 需要先设置进度条增量：increaseProgress
     *
     * @author Eugenema
     * @date 2023/4/18 21:50
     **/
    public static void progressAdd() {
        // 进度不能超过 100%
        if (progress.get() + increaseProgress > 1) {
            increaseProgress = 1 - progress.get();
        }
        //在 JavaFx 线程中更新进度条标签
        Platform.runLater(() -> progress.set(progress.get() + increaseProgress));
    }

    /**
     * 打开需求参数编辑弹窗
     *
     * @param key 识别应该加载哪个参数配置文件
     *
     * @author Eugenema
     * @date 2023/5/5 20:35
     **/
    @FXML
    private void editParameter(ActionEvent event, String key) {
        //获取需求对应的参数 map
        switch (key) {
            case DemandF5Schedule.DEMAND_ONE_PARAMETER_KEY: {
                initializeConfigFile(DemandF5Schedule.DEMAND_ONE_PARAMETER_KEY, ConfigUtil.DEMAND_ONE_CONFIG, null);
                break;
            }
            case DemandF5RedGemBook.DEMAND_TWO_PARAMETER_KEY: {
                initializeConfigFile(DemandF5RedGemBook.DEMAND_TWO_PARAMETER_KEY, ConfigUtil.DEMAND_TWO_CONFIG, null);
                break;
            }
            case DemandF2Schedule.DEMAND_THREE_PARAMETER_KEY: {
                initializeConfigFile(DemandF2Schedule.DEMAND_THREE_PARAMETER_KEY, ConfigUtil.DEMAND_THREE_CONFIG, null);
                break;
            }
            default: {
                return;
            }
        }

        //显示弹窗
        if (!editParameterDialog.isVisible()) {
            editParameterDialog.setTransitionType(DialogTransition.CENTER);
            editParameterDialog.show((StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_HOME_CONTENT));
        }
    }

    /**
     * 初始化配置文件
     *
     * @param key           配置文件 key
     * @param openConfigKey 当前打开的文件 key
     * @param openFile      当前打开的文件，为空则取配置文件中的值
     * @return
     * @author Eugenema
     * @date 2023/10/17 21:52
     **/
    private boolean initializeConfigFile(String key, String openConfigKey, String openFile) {
        // 更新当前配置文件参数 key、当前打开配置文件 key、当前打开配置文件
        openingConfigParameterKey = key;
        openingConfigKey = openConfigKey;
        if (openFile == null) {
            openingConfigFile = ConfigUtil.getProperty(openingConfigKey);
            //加载 Script 文件的参数
            SeleniumXmlParseUtil.parseParameter(openingConfigFile);
        } else {
            //加载 Script 文件的参数
            SeleniumXmlParseUtil.parseParameter(openFile);
        }

        return loadParameterData();
    }

    /**
     * 加载参数数据
     *
     * @return 格式化之后的 xml 参数
     * @author Eugenema
     * @date 2023/5/5 21:37
     **/
    private boolean loadParameterData() {
        //获取解析 Xml 文件的参数
        Map<String, String> parameterMap = (Map<String, String>) SeleniumXmlParseUtil.parameterMap.get(openingConfigParameterKey);

        if (parameterMap == null) {
            repetitionAlert.setTitle("加载失败");
            repetitionAlert.setHeaderText("文件选择错误");
            repetitionAlert.setContentText("不是该需求的配置文件，请重新选择！");
            repetitionAlert.show();
            return false;
        }

        //将参数 key 存入弹窗标签中
        leagueKey.setText(openingConfigParameterKey);
        // 更新弹窗标题
        updateDialogTitle();

        //转换成表格类型
        parameterData = FXCollections.observableArrayList();
        for (Map.Entry<String, String> parameterEntry : parameterMap.entrySet()) {
            parameterData.add(new ParameterMap(openingConfigParameterKey, parameterEntry.getKey(), parameterEntry.getValue()));
        }

        //载入表格
        parameterTable.setRoot(new RecursiveTreeItem<>(parameterData, RecursiveTreeObject::getChildren));
        return true;
    }

    /**
     * 绑定列与数据之间的关系
     *
     * @param column 列
     * @param mapper 数据
     * @author Eugenema
     * @date 2023/5/5 22:02
     **/
    private <T> void setupCellValueFactory(JFXTreeTableColumn<ParameterMap, T> column, Function<ParameterMap, ObservableValue<T>> mapper) {
        column.setCellValueFactory((TreeTableColumn.CellDataFeatures<ParameterMap, T> param) -> {
            if (column.validateValue(param)) {
                return mapper.apply(param.getValue().getValue());
            } else {
                return column.getComputedValue(param);
            }
        });
    }

    /**
     * 关闭参数编辑弹窗
     *
     * @author 马寅广
     * @date 2023/5/6 16:52
     **/
    @FXML
    private void closeEditParameterDialog() {
        confirmAlert.setOnHidden(evt -> {
            if (confirmAlert.getResult() == ButtonType.OK) {
                editParameterDialog.close();
            }
        });
        confirmAlert.show();
    }

    /**
     * 导入F5填赛果目标球队
     *
     * @author Eugenema
     * @date 2023/11/26 20:16
     *
     **/
    @FXML
    private void importParameter() {
        if (DemandF5FillMatchResult.targetLinkList.isEmpty()) {
            repetitionAlert.setTitle("导入失败");
            repetitionAlert.setHeaderText("数据为空");
            repetitionAlert.setContentText("可能未执行F5填赛果，请执行后再运行导入！");
            repetitionAlert.show();
        } else {
            DemandF5FillMatchResult.targetLinkList.forEach(data -> {
                parameterData.add(new ParameterMap(openingConfigParameterKey, data.get(2), data.get(1)));
            });
        }
    }

    /**
     * 保存编辑后的参数
     *
     * @author 马寅广
     * @date 2023/5/6 16:57
     **/
    @FXML
    private void saveEditParameterResult() {
        if (saveCheck()) {
            SeleniumXmlParseUtil.writeParameter(openingConfigFile, parameterData);
            successAlert.show();
            // 保存成功后，重新加载配置文件
            editParameter(null, openingConfigParameterKey);
        }
    }

    /**
     * 保存参数检查
     *
     * @return
     * @author Eugenema
     * @date 2023/10/21 23:33
     **/
    private boolean saveCheck() {
        //检查联赛/球队名称，禁止重复
        boolean repetition = parameterData.stream().map(parameterMap -> parameterMap.nameProperty().get()).distinct().count() < parameterData.size();
        if (repetition) {
            repetitionAlert.setTitle("保存失败");
            repetitionAlert.setHeaderText("联赛/球队名称重复，禁止保存！");
            repetitionAlert.setContentText("请修改重复的联赛/球队名称，然后再进行保存！");
            repetitionAlert.show();
            return false;
        }

        //至少有一个联赛/球队
        if (parameterData.size() < 1) {
            repetitionAlert.setTitle("保存失败");
            repetitionAlert.setHeaderText("参数列表为空，禁止保存！");
            repetitionAlert.setContentText("请至少添加一个参数，再进行保存！");
            repetitionAlert.show();
            return false;
        }
        return true;
    }

    /**
     * 加载配置文件
     *
     * @param event
     * @return
     * @author Eugenema
     * @date 2023/10/17 21:32
     **/
    @FXML
    private void loadConfigFile(ActionEvent event) {
        /** 文件选择器 */
        FileChooser fileChooser = new FileChooser();
        // 默认打开路径：当前配置文件所在路径
        fileChooser.setInitialDirectory(new File(SeleniumXmlParseUtil.PARSE_XML_PATH));
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("配置文件", "*.xml"));
        File file = fileChooser.showOpenDialog(stage);
        if (file != null) {
            // 设置当前打开的配置文件并加载参数
            if (initializeConfigFile(openingConfigParameterKey, openingConfigKey, file.getAbsolutePath())) {
                updateLoadXml(file);
            } else {
                // 打开文件失败，但是由于已经加载了文件内容，只是没有更新配置。所以需要重新加载一次配置中的文件内容
                initializeConfigFile(openingConfigParameterKey, openingConfigKey, null);
            }
        }
    }

    /**
     * 配置另存为
     *
     * @param event
     * @return
     * @author Eugenema
     * @date 2023/10/17 22:17
     **/
    @FXML
    private void saveAsConfigFile(ActionEvent event) {
        // 参数检查
        if (!saveCheck()) {
            return;
        }

        /** 文件选择器 */
        FileChooser fileChooser = new FileChooser();
        // 默认打开路径：当前配置文件所在路径
        fileChooser.setInitialDirectory(new File(SeleniumXmlParseUtil.PARSE_XML_PATH));
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("配置文件", "*.xml"));
        File file = fileChooser.showSaveDialog(stage);
        if (file != null) {
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (SeleniumXmlParseUtil.createParameterXml(file, parameterData)) {
                successAlert.show();
                // 更新当前打开的配置文件信息
                updateLoadXml(file);
            } else {
                repetitionAlert.setTitle("另存为失败");
                repetitionAlert.setHeaderText("配置文件另存为失败");
                repetitionAlert.setContentText("具体错误内容，请查看日志！");
                repetitionAlert.show();
            }
        }
    }

    /**
     * 更新弹窗标题
     *
     * @author Eugenema
     * @date 2023/10/21 23:24
     **/
    public void updateDialogTitle() {
        // 将配置文件名称存入弹窗标题中
        String fileName = "默认配置文件";
        Pattern p = compile("(?:.*\\\\)?([^\\\\]+?)(?:\\.xml)?");
        Matcher matcher = p.matcher(openingConfigFile);
        if (matcher.matches()) {
            fileName = matcher.group(1);
        }
        editParameterDialogTitle.setText(String.join("", "需求参数编辑（", fileName, "）"));
    }

    /**
     * 更新加载的配置文件信息
     *
     * @param file 当前配置文件
     * @author Eugenema
     * @date 2023/10/21 23:26
     **/
    public void updateLoadXml(File file) {
        // 更新配置文件，将另存为的文件作为当前配置文件
        Map<String, String> parameter = new HashMap<>(1);
        parameter.put(openingConfigKey, file.getAbsolutePath());
        ConfigUtil.setProperty(parameter);
        // 更新当前打开文件常量标识
        openingConfigFile = file.getAbsolutePath();
        // 更新弹框标题
        updateDialogTitle();
    }

    /**
     * 展示自定义弹窗
     *
     * @author 马寅广
     * @date 2024/1/1 15:03
     *
     * @param event
     * @param dialog 弹窗
     *
     **/
    public void showDialog(ActionEvent event, JFXDialog dialog) {
        dialog.show((StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_MAIN_CONTENT));
    }
}